#include "Number.h"
#include "MQTT/MQTTError.h"

int32_t string2Uint32(char *input, uint8_t inputLen, uint32_t *output) {

    uint8_t index = 0;
    uint32_t temp = 0;

    for (index = 0; index < inputLen; index++) {

        if (input[index] < '0' || input[index] > '9') {
            return paramsOutOfRange;
        }

        temp = temp * 10 + input[index] - '0';
    }

    *output = temp;
    return aiotSuccess;
}

int32_t string2Uint64(char *input, uint8_t inputLen, uint64_t *output) {

    uint8_t index = 0;
    uint64_t temp = 0;

    for (index = 0; index < inputLen; index++) {
        if (input[index] < '0' || input[index] > '9') {
            return paramsOutOfRange;
        }

        temp = temp * 10 + input[index] - '0';
    }

    *output = temp;
    return aiotSuccess;
}

int32_t uint32ToString(uint32_t input, char *output, uint8_t *outputLen) {

    uint8_t i = 0, j = 0;
    char temp[10] = {0};

    do {
        temp[i++] = input % 10 + '0';
    } while ((input /= 10) > 0);

    do {
        output[--i] = temp[j++];
    } while (i > 0);

    if (outputLen) {
        *outputLen = j;
    }

    return aiotSuccess;
}

int32_t uint64ToString(uint64_t input, char *output, uint8_t *outputLen) {

    uint8_t i = 0, j = 0;
    char temp[20] = {0};

    do {
        temp[i++] = input % 10 + '0';
    } while ((input /= 10) > 0);

    do {
        output[--i] = temp[j++];
    } while (i > 0);

    if (outputLen) {
        *outputLen = j;
    }

    return aiotSuccess;
}

int32_t int32ToString(int32_t input, char *output, uint8_t *outputLen) {

    uint8_t i = 0, j = 0, minus = 0;
    char temp[11] = {0};
    int64_t in = input;

    if (in < 0) {
        minus = 1;
        in = -in;
    }

    do {
        temp[minus + (i++)] = in % 10 + '0';
    } while ((in /= 10) > 0);

    do {
        output[minus + (--i)] = temp[minus + (j++)];
    } while (i > 0);

    if (minus == 1) {
        output[0] = '-';
    }

    if (outputLen) {
        *outputLen = j + minus;
    }

    return aiotSuccess;
}

int32_t int32ToHexStr(int32_t input, char *output, uint8_t *outputLen) {

    char *lower = "0123456789abcdef";
    uint8_t i = 0, j = 0;
    uint8_t nagative = 0;
    char temp[12] = {0};
    if(input < 0){
        nagative = 1;
        input *= -1;
    }

    do {
        temp[i++] = lower[input % 16];
    } while ((input /= 16) > 0);

    temp[i++] = 'x';
    temp[i++] = '0';
    if(nagative){
        temp[i++] = '-';
    }

    do {
        output[--i] = temp[j++];
    } while (i > 0);

    if (outputLen) {
        *outputLen = j;
    }

    return aiotSuccess;
}

int32_t hex2String(uint8_t *input, uint32_t inputLen, char *output, uint8_t lowercase) {

    char *upper = "0123456789ABCDEF";
    char *lower = "0123456789abcdef";
    char *encode = upper;
    int i = 0, j = 0;

    if (lowercase) {
        encode = lower;
    }

    for (i = 0; i < inputLen; i++) {
        output[j++] = encode[(input[i] >> 4) & 0xf];
        output[j++] = encode[(input[i]) & 0xf];
    }

    return aiotSuccess;
}

int32_t string2hex(char *input, uint32_t inputLen, uint8_t *output) {

    uint32_t idx = 0;

    if (inputLen % 2 != 0) {
        return paramsOutOfRange;
    }

    for (idx = 0; idx < inputLen; idx += 2) {
        if (input[idx] >= '0' && input[idx] <= '9') {
            output[idx / 2] = (input[idx] - '0') << 4;
        } else if (input[idx] >= 'A' && input[idx] <= 'F') {
            output[idx / 2] = (input[idx] - 'A' + 0x0A) << 4;
        } else if (input[idx] >= 'a' && input[idx] <= 'f') {
            output[idx / 2] = (input[idx] - 'a' + 0x0A) << 4;
        }
        if (input[idx + 1] >= '0' && input[idx + 1] <= '9') {
            output[idx / 2] |= (input[idx + 1] - '0');
        } else if (input[idx + 1] >= 'A' && input[idx + 1] <= 'F') {
            output[idx / 2] |= (input[idx + 1] - 'A' + 0x0A);
        } else if (input[idx + 1] >= 'a' && input[idx + 1] <= 'f') {
            output[idx / 2] |= (input[idx + 1] - 'a' + 0x0A);
        }
    }

    return aiotSuccess;
}

int32_t utc2date(uint64_t utc, int8_t zone, DateDefine *date) {

    uint32_t day_sec = 0, day_num = 0;
    uint64_t utc_zone_s = 0;

#define DAYS_IN_YEAR(year)        (IS_LEAP_YEAR(year) ? 366 : 365)
#define IS_LEAP_YEAR(year)        (!((year) % 400) || (((year) % 100) && !((year) % 4)))
#define DAYS_IN_MONTH(lpyr, mon)  ((mon == 1)?(28 + lpyr):((mon > 6)?(((mon - 1) & 1)?(30):(31)):((mon & 1)?(30):(31))))

    date->msec = utc % 1000;
    utc_zone_s = (utc / 1000) + (zone * 60 * 60);

    day_sec = utc_zone_s % (24 * 60 * 60);
    day_num = utc_zone_s / (24 * 60 * 60);

    date->sec = day_sec % 60;
    date->min = (day_sec % 3600) / 60;
    date->hour = day_sec / 3600;

    date->year = 1970;
    while (day_num >= DAYS_IN_YEAR(date->year)) {
        day_num -= DAYS_IN_YEAR(date->year);
        date->year++;
    }

    date->mon = 0;
    while (day_num >= DAYS_IN_MONTH(IS_LEAP_YEAR(date->year), date->mon)) {
        day_num -= DAYS_IN_MONTH(IS_LEAP_YEAR(date->year), date->mon);
        date->mon++;
    }

    date->mon++;
    date->day = day_num + 1;

    return 0;
}